#!/usr/bin/env python3.9
# Find the longest-traveled message in the input & generate an APRS telemetry packet
# As seen on https://aprs.fi/telemetry/a/VK2CJB-1.
# --
# Chris Baird,, vk2cjb@gmail.com, April 2022

from geopy import distance
import sys, re, time, curses, aprspy, signal, os
aprspy.logger.setLevel("ERROR") # stop that module spewing to stdout

timerange = 1200

# it helps acquistion to put in a few fixed stations, and to resolve
# any chance DX where any intermediate digis might not have been heard
# before.
pos = {
    "VK1RGI-1" : (-35.526662, 148.769478),
    "VK2AMW-1" : (-34.5535, 150.629333),
    "VK2BWI-1" : (-33.699167, 151.055167),
    "VK2CJB-1" : (-32.912333, 151.312333),
    "VK2EVB-1" : (-30.280667, 153.124167),
    "VK2HUB-5" : (-33.84, 151.1085),
    "VK2RAB-1" : (-31.587833, 150.992667),
    "VK2RAG-1" : (-33.361167, 151.291),
    "VK2RCC-1" : (-31.271667, 149.061667),
    "VK2RHR-1" : (-34.370667, 150.3355),
    "VK2RMI-1" : (-29.807667, 150.278833),
    "VK2RMY-1" : (-30.813833, 152.9195),
    "VK2RNW-1" : (-30.278833, 150.1525),
    "VK2RPM-1" : (-31.701833, 152.678333),
    "VK2RTZ-1" : (-32.941, 151.515),
    "VK2UNI-1" : (-31.921667, 152.182167),
    "VK2XSO-1" : (-31.277333, 151.85),
    "VK2XSO-3" : (-30.008, 151.693833),
    "VK2ZSI-1" : (-30.9855, 150.243833),
    "VK3RGR-1" : (-36.438333, 146.248333),
    "VK3RHO-1" : (-36.975, 147.128),
    "VK3RNU-1" : (-36.451333, 146.803),
    "VK4RCR-3" : (-28.387833, 151.921667)
}
pos["TERMINUS"] = (-32.912333, 151.312333) # location of this receiver
tally = { "VK2RTZ-1" : 19.220 } # bootstrap the nearest repeater
allstations, tallyfar, msgcount = {}, {}, 0
hour, minute, seconds = time.localtime()[3:6]
now = 3600*hour + 60*minute + seconds

# ----------------------------------------------------------------------

while True:
    aprsmsg = sys.stdin.readline()
    if aprsmsg == "": break
    aprsmsg = aprsmsg.encode('ascii',errors='ignore').decode().rstrip()

    g = re.match(r"^\[([0-9]+) (\d+):(\d+):(\d+)\]", aprsmsg)
    if g == None: continue
    g = g.groups()
    pkttime = 3600*int(g[1]) + 60*int(g[2]) + int(g[3])

    if (now < pkttime): pkttime -= 86400
    pktrecent = False
    if (pkttime - now) <= timerange and (now - pkttime) <= timerange:
        pktrecent = True
        msgcount += 1

    aprsmsg = re.sub("^\[[0-9: ]+\] ", "", aprsmsg) # remove kissutil log cruft

    if not re.search("^(\d?[a-z]{1,3}|[a-z]\d[a-z]?)\d[a-z]{1,3}(\-1?[1-9]+)?>", \
                     aprsmsg, re.IGNORECASE):
        continue

    try:
        f = aprspy.APRS.parse(aprsmsg)
        coord = (f.latitude, f.longitude)
    except:
        continue

    s = f.source
    if pktrecent == True: allstations[s] = 1
    pos[s] = lastcoord = (coord)
    dist = 0
    path = str(f.path) + ",TERMINUS"
    for r in path.split(','):
        if "WIDE" in r or "RFONLY" in r or "NOGATE" in r: continue
        d = r.rstrip('*')
        if d != "TERMINUS" and pktrecent == True: allstations[d] = 1
        if d in pos:
            coord = pos[d]
            dist += distance.distance(coord, lastcoord).km
            lastcoord = coord
        else:
            dist = -100000000

    if dist > 0 and dist < 5000 and pktrecent == True:
        tally[s] = dist
        if not s in tallyfar: tallyfar[s] = dist
        if dist > tallyfar[s]: tallyfar[s] = dist

# ----------------------------------------------------------------------

i = sorted(tallyfar, key=tallyfar.get, reverse=True)[0]
seq = int((time.time()-1620188367)/600.0)%1000
d = int(tallyfar[i]*100)
numstats = len(allstations)
pph = int(10*msgcount*(3600.0/timerange))

s = "VK2CJB-1>APRS,WIDE1-1,WIDE2-1:T#{:03d},{:03d},{:03d},{:03d}\n"
if hour % 6 == 0 and minute < 3:
    s = """VK2CJB-1>APRS,WIDE1-1,WIDE2-1::VK2CJB-1 :PARM.Dist,Statns,MsgCntHr
VK2CJB-1>APRS,WIDE1-1,WIDE2-1::VK2CJB-1 :UNIT.KM,Integer,Integer
VK2CJB-1>APRS,WIDE1-1,WIDE2-1::VK2CJB-1 :EQNS.0,0.01,0,0,1,0,0,0.1,0
VK2CJB-1>APRS,WIDE1-1,WIDE2-1::VK2CJB-1 :BITS.00000000,Max APRS path seen
""" + s

outfile = "/var/spool/packet/send/000-telemetry"
if len(sys.argv) > 1: outfile = "/dev/stdout"
foo = open(outfile, mode='w')
foo.write(s.format(seq, d, numstats, pph))
foo.close()

# ----------------------------------------------------------------------
